
******************************************************************************
* Math
*
* (C)  Copyright Apple Computer, Inc. 1988
* All rights reserved.
*
* by Jim Mensch
* 7/14/88
*
* Sample to show how to use the Integer math and SANE tools. This program shows
* 2 basic operations performed both with the integer math tools and SANE. The
* first is the calculation and display of a simple SINE curve. The second is
* a more complex Fast Fourier Transform.
*
* Files:            System macros and equates
*
*
*
* Modification History:
*
* Version 1.0       Mensch
*
*      7/14/88
*
*      Initial release
*
*******************************************************************************
*                                                                    *
*             Apple IIGS Source Code Sampler, Volume I               *
*                                                                    *
*             Copyright (c) Apple Computer, Inc. 1988                *
*                       All Rights Reserved                          *
*                                                                    *
*            Written by Apple II Developer Tech Support              *
*                                                                    *
*                                                                    *
*                                                                    *
*  ----------------------------------------------------------------  *
*                                                                    *
*     This program and its derivatives are licensed only for         *
*     use on Apple computers.                                        *
*                                                                    *
*     Works based on this program must contain and                   *
*     conspicuously display this notice.                             *
*                                                                    *
*     This software is provided for your evaluation and to           *
*     assist you in developing software for the Apple IIGS           *
*     computer.                                                      *
*                                                                    *
*     DISCLAIMER OF WARRANTY                                         *
*                                                                    *
*     THE SOFTWARE IS PROVIDED "AS IS" WITHOUT                       *
*     WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,               *
*     WITH RESPECT TO ITS MERCHANTABILITY OR ITS FITNESS             *
*     FOR ANY PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO             *
*     THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH            *
*     YOU.  SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU (AND            *
*     NOT APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE)               *
*     ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING,             *
*     REPAIR OR CORRECTION.                                          *
*                                                                    *
*     Apple does not warrant that the functions                      *
*     contained in the Software will meet your requirements          *
*     or that the operation of the Software will be                  *
*     uninterrupted or error free or that defects in the             *
*     Software will be corrected.                                    *
*                                                                    *
*     SOME STATES DO NOT ALLOW THE EXCLUSION                         *
*     OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY              *
*     NOT APPLY TO YOU.  THIS WARRANTY GIVES YOU SPECIFIC            *
*     LEGAL RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS                *
*     WHICH VARY FROM STATE TO STATE.                                *
*                                                                    *
*                                                                    *
**********************************************************************

                    mcopy math.macros
                    copy 2/ainclude/E16.Quickdraw
                    copy 2/ainclude/E16.Memory
                    copy 2/ainclude/E16.Window
                    copy 2/ainclude/E16.Dialog
                    copy 2/ainclude/E16.SANE

DPHandle            gequ 0
DPPointer           gequ DPHandle+4
DeRef               gequ DPPointer+4

ScreenWidth         gequ 640
ScreenMode          gequ $80


                    EJECT
*******************************************************************************
*
Math                start
*
* Description:      This main routine calls the other major routines in the 
*                   correct order.
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:
*                   Import QuitParms
*                   Import InitTools
*                   Import InitApp
*                   Import EventLoop
*                   Import CloseTools
*                   Import CloseApp
*
* Entry Points:     None
*
*******************************************************************************
                    using globals
                    jsr InitTools
                    jsr InitApp

                    _ShowCursor

                    jsr EventLoop
                    jsr CloseApp
                    jsr CloseTools

                    _Quit QuitParms

                    end

                    EJECT
*******************************************************************************
*
Globals             data
*
* Description:      Global data for use in all routines of this demo. This area
*                   also contains the data used by StandardLib.aii              
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:    None
*
* Entry Points:
*                   Export QuitParms    ; used by Main
*
*******************************************************************************
*
* Standard global data
*
*******************************************************************************

TitleString         str 'Apple IIgs Integer Math/Sane demo'
AutString           str 'By Jim Mensch Apple DTS (c)1988 Apple Computer'
VersString          str 'Version: 1.0'


MenuHeight          ds 2                ; Stored height of menu bar
MyID                ds 2                ; Application ID
MyDP                ds 2                ; My direct page storage

QuitFlag            ds 2
QuitParms           dc i4'0'            ; Pathname of next app
                    dc i2'$00'          ; flags

EventRecord         ANOP
EventWhat           ds 2
EventMessage        ds 4
EventWhen           ds 4
EventWhere          ds 4
EventModifiers      ds 2
TaskData            ds 4
TaskMask            dc i4'$0000FFFF'

                    EJECT
*******************************************************************************
*
* Application specific global data
*
*******************************************************************************

; This is a list of pointers to the text that is used to create our menus. It
; is used by InitApp to find all of the menu templates and use them to create
; our menubar. This loop loads MenuPtrLen-4 into an index, gets the
; corresponding menu template pointer in this table, and uses that in a
; NewMenu call. It then decrements the index by 4, and repeats the procees
; until the index is negative.

MenuPtr             dc i4'AppMenu'
                    dc i4'FileMenu'
MenuPtrLen          equ *-MenuPtr


; Menu list: menu items should be numbered consecutivly starting from 250.
; As a convention, use 256 as about and 257 as Quit.



AppMenu             dc c'$$@\N1',h'0D'
                    dc c'--About Math...\N256U',h'00'
                    dc c'.'
FileMenu            dc c'$$  File\N2',h'0D'
                    dc c'--SANE Fast Fourier transform\N260',h'00'
                    dc c'--Integer Fast Fourier transform\N261',h'00'
                    dc c'--Integer Sine wave\N258*Ii',h'00'
                    dc c'--SANE Sine wave\N259*SsV',h'00'
                    dc c'--Quit\N257*Qq',h'00'
                    dc c'.'

; Paramater block used to create the main window for display. All the
; graphing routines will use this window to draw into.

MyWindow            dc i2'WindEnd-*'    ; size of paramBlock
                    dc i2'%0010000000100000' ; frame bits : alert, vis
                    dc i4'0'            ; no title bar, no title...
                    dc i4'0'            ; ref con 0
                    dc i2'0,0,0,0'      ; zoomed rect
                    dc i4'0'            ; color table = default
                    dc i2'0,0'          ; scroll bar XY origin
                    dc i2'0,0'          ; no scroll no max...
                    dc i2'0,0'          ; No zooming...
                    dc i2'0,0'          ; no scrolling
                    dc i2'0,0'          ; no paging....
                    dc i4'0'            ; no info bar, no ref con
                    dc i2'0'            ; info bar height ( none...)
                    dc i4'0'            ; Frame defproc, NIL=standard
                    dc i4'0'            ; no info bar def proc
                    dc i4'0'            ; no auto updates.. (yet)
                    dc i2'20,20,195,619'                    ; bounds rect...
                    dc i4'$FFFFFFFF'    ; plane= on top...
                    dc i4'0'            ; NIL storage pointer
WindEnd             equ *
ContRect            dc i2'0,0,180,599'  ; content rectangle

WindPointer         ds 4

; Constants used thru the program both represent PI*2

twoPi               dc i1'$1D,$72,$33,$DC,$80,$CF,$0F,$C9,$01,$40'
twoPiFix            dc i2'$487E,$0006'

; Titles for the bottom of the window

IntSineTitle        str 'Integer Math Demo: plotting Y=SIN(X)'
SANESineTitle       str 'SANE Demo: plotting Y=SIN(X)'
IntHarmTitle        str 'Integer Math Demo: plotting complex waveform'
SANEHarmTitle       str 'SANE Demo: plotting complex waveform'
                    end
                    
                    EJECT
*******************************************************************************
*
InitApp             start
*
* Description:      This routine creates our window and zeros out the quitflag
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:    None
*
* Entry Points:     None
*
*******************************************************************************
                    using Globals

                    Stz QuitFlag        ; zero out quit flag

                    PushLong #0
                    PushLong #MyWindow
                    _NewWindow          ; create a window to graph in
                    PullLong WindPointer

                    PushLong WindPointer
                    _SetPort            ; make the new window the current port

                    rts
                    end

                    EJECT
*******************************************************************************
*
CloseApp            start
*
* Description:      This routine will be called at program end to dispose of
*                   the window.
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:    None
*
* Entry Points:     None
*
*******************************************************************************
                    using Globals

                    PushLong WindPointer
                    _CloseWindow

                    rts
                    end

                    EJECT
*******************************************************************************
*
EventLoop           start
*
* Description:      Main loop. Handles events until the user selects quit
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:
*                   Import Ignore
*                   Import MenuSelect
*
* Entry Points:
*
*******************************************************************************
                    using Globals


                    pha                 ; Push on space for TaskMaster result
                    PushWord #$FFFF     ; GetNextEvent mask
                    PushLong #EventRecord ; Pointer to Event Record
                    _TaskMaster

                    pla                 ; Get TaskMaster result
                    beq EventLoop       ; Remove if you want to use null events
                    asl A               ; Turn it into an index
                    tax
                    jsr (TaskTable,x)   ; Call appropriate event handler

                    lda QuitFlag        ; Quit selected?
                    beq EventLoop       ; no - keep looping

                    rts                 ; yes- leave the program


TaskTable           dc i2'Ignore'       ; 0 Null
                    dc i2'Ignore'       ; 1 MouseDown
                    dc i2'Ignore'       ; 2 Mouse Up
                    dc i2'Ignore'       ; 3 KeyDown
                    dc i2'Ignore'       ; 4 Undefined
                    dc i2'Ignore'       ; 5 AutoKey
                    dc i2'Ignore'       ; 6 Update
                    dc i2'Ignore'       ; 7 undefined
                    dc i2'Ignore'       ; 8 activate
                    dc i2'Ignore'       ; 9 Switch
                    dc i2'Ignore'       ; 10 desk acc
                    dc i2'Ignore'       ; 11 device driver
                    dc i2'Ignore'       ; 12 ap
                    dc i2'Ignore'       ; 13 ap
                    dc i2'Ignore'       ; 14 ap
                    dc i2'Ignore'       ; 15 ap
                    dc i2'Ignore'       ; TASK 0 indesk
                    dc i2'MenuSelect'   ; TASK 1 in menuBar
                    dc i2'Ignore'       ; TASK 2 in system window
                    dc i2'Ignore'       ; TASK 3 in content
                    dc i2'Ignore'       ; TASK 4 in Drag
                    dc i2'Ignore'       ; TASK 5 in grow
                    dc i2'Ignore'       ; TASK 6 in goaway
                    dc i2'Ignore'       ; TASK 7 in zoom
                    dc i2'Ignore'       ; TASK 8 in info bar
                    dc i2'Ignore'       ; TASK 9 in special menu
                    dc i2'Ignore'       ; TASK 10 in NDA
                    dc i2'Ignore'       ; TASK 11 in frame
                    dc i2'Ignore'       ; TASK 12 in drop           

                    end
                    
                    EJECT
*******************************************************************************
*
MenuSelect          start
*
* Description:      This routine is called when taskmaster returns a code
*                   indicating that the user selected one of our menu options.
*                   This routine will call whatever routine is indicated for
*                   each menu action
*
*
* Inputs:           TaskData - menu selected by the user
*
* Outputs:          None
*
* External Refs:
*                   Import Ignore
*                   Import DoAbout
*                   Import DoQuit
*                   Import IntSinecurve
*                   Import SANESineCurve
*                   Import IntHarmWave
*                   Import SANEHarmWave
*
* Entry Points:
*
*******************************************************************************
                    using Globals

                    lda TaskData        ; get the ID of the menu item selected
                    sec                 ; adjust it to be between 0 and 5
                    sbc #256
                    asl a               ; multiply it by 2
                    tax                 ; and use it as an index into our jump
                    jsr (menuTable,x)   ; table.

MSDone              ANOP
                    PushWord #0         ; menu action complete, unhilite the
                    PushWord taskData+2 ; selected menu to show we are done
                    _HiLiteMenu

                    rts                 ; and quit

MenuTable           dc i2'DoAbout'      ; about shell...
                    dc i2'DoQuit'       ; quit selected
                    dc i2'IntSineCurve' ; draw integer math sine wave
                    dc i2'SANESineCurve'                    ; draw sane sine wave
                    dc i2'SANEHarmWave'
                    dc i2'IntHarmWave'
                    end

                    EJECT
*******************************************************************************
*
DoQuit              start
*
* Description:      Sets the quit flag to inform the event loop that the user
*                   wants to stop the program
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:    None
*
* Entry Points:     None
*
*******************************************************************************
                    using Globals

                    lda #$FFFF
                    sta QuitFlag
                    rts
                    end

*******************************************************************************
*
Ignore              start
*
* Description:      Called when the program gets an event or menu selection that
*                   it does not want to handle
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:    None
*
* Entry Points:     None
*
*******************************************************************************
                    rts
                    end

                    EJECT
*******************************************************************************
*
IntSineCurve        start
*
* Description:      This routine will calculate a simple Sine curve and display
*                   it graphically on the screen.           
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:    None
*
* Entry Points:     None
*
*******************************************************************************
                    using Globals

                    PushLong #ContRect  ; first, start with a clean screen
                    _EraseRect          ; by erasing the old screen

                    PushWord #10        ; label the bottom of the window
                    PushWord #170       ; to show what we are doing
                    _MoveTo
                    
                    PushLong #IntSineTitle
                    _DrawString
                    
                    stzL LoopCount      ; zero the counter to start this thing

                    PushWord #0         ; start this drawing off
                    PushWord #80
                    _MoveTo


DIMLoop             ANOP
                    LongResult          ; space for results here for all the
                    LongResult          ; following calculations. by pushing
                    LongResult          ; the space here, we do not need to 
                    LongResult          ; adjust the stack between int math calls
                    LongResult          ; and we save time and space
                    
                    PushLong LoopCount  ; Calc: LoopCount/180
                    PushLong One80      ; 
                    _FixDiv             ; leave result on stack for next calc
                                        
                    PushLong RFixPi     ; Calc (LoopCount/180)*PI
                    _FixMul             ; to convert LoopCount to radians
                    
                    _fracSin            ; take the sine of the counter
                    
                    _Frac2Fix           ; convert it back to fixed #
                    
                    PushLong Eighty     ; multiply it by 80 to scale
                    _FixMul             ; we have our number!
                    PullLong YCord      ; and its the y coordinate

                    PushWord LoopCount+2 ; X coordinate (HiWord of Fixed)
                    lda YCord+2         ; Y coordinate + 80
                    clc                 ; to scale the number between
                    adc #80             ; 0 and 160
                    pha
                    _LineTo             ; draw the linesegment for this point

                    inc LoopCount+2     ; bump the loopcounter
                    lda LoopCount+2     ; and see if we have reached 360
                    cmp #360            ; for a full SINE curve
                    bge DIMDone         ; if so, then finish the loop
                    brl DIMLoop         ; if not do the next iteration
DIMDone             ANOP
                    rts                 ; finish the routine
LoopCount           ds 4                ; Fixed number to store degrees
one80               dc i2'0,180'        ; a fixed number representing 180
Eighty              dc i2'0,80'         ; a FIxed number represenging 80
YCord               ds 4                ; temp storage for the y coordinate
RFixPi              dc i4'$0003243F'    ; 3.14159 (PI in fixed format)
                    end

                    EJECT
*******************************************************************************
*
SANESineCurve       start
*
* Description:      This routine will use the SANE toolset to calculate
*                   a Sine curve. It will then plot the points on the screen.
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:    None
*
* Entry Points:     None
*
*******************************************************************************
                    using Globals
                    using SANEequs
                    PushLong #ContRect  ; first, start with a clean screen
                    _EraseRect          ; by erasing the old screen

                    PushWord #10        ; label the bottom of the window
                    PushWord #170       ; to show what we are doing
                    _MoveTo
                    
                    PushLong #SANESineTitle
                    _DrawString
                    
                    PushWord #0         ; start this drawing off
                    PushWord #80        ; in the middle of the screen
                    _MoveTo
                    
                    stz LoopCount

DSaneLoop           ANOP
                    ExtendEq SanePi,TempResult ; move pi/180 into the result

                    PushLong #LoopCount ; convert LoopCount to Radians
                    PushLong #TempResult
                    FMULI               ; by multiplying by pi/180

                    PushLong #TempResult
                    FSINX               ; now get the SINE of it

                    PushLong #Eighty    ; multiply by 80
                    PushLong #TempResult
                    FMULI

                    PushLong #TempResult
                    PushLong #YCord     ; convert to an Integer
                    FX2I

                    PushWord LoopCount  ; X coordinate
                    lda YCord           ; Y coordinate + 80
                    clc                 ; to get a number between 
                    adc #80             ; 0 and 160
                    pha
                    _LineTo             ; draw the line segement

                    inc LoopCount       ; bump the counter
                    lda LoopCount
                    cmp #360            ; and see if we have done all 360 degrees
                    bge DSaneDone       ; if so then end
                    brl DSaneLoop       ; if not, get next value
DSaneDone           ANOP
                    rts
LoopCount           ds 4
SanePI              dc i1'$AE,$C8,$E9,$94,$12,$35,$FA,$8E,$F9,$3F' ; pi/180 ...
TempResult          ds 10
Eighty              dc i4'80'
YCord               ds 4
                    end


                    EJECT
*******************************************************************************
*
FFTransData         data
*
* Description:      Data used by both FFT calculation routines
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:    None
*
* Entry Points:     None
*
*******************************************************************************

FixCount            dc i2'0'            ; fractional portsion of our
Count               ds 2                ; fixed point counter
LoopCount           ds 2
FixSamp             dc i2'0'            ; fractional portion of the sample var
Sample              ds 2                ; sample to figure for
FixMaxSamp          dc i2'0'            ; fractional portion of Max Sample
MaxSample           dc i2'256'          ; maximum number of samples
MaxHarm             dc i2'6'            ; maximum number of harmonics
MaxValue            ds 10               ; maximum vaule of the FFT
AmpTbl              dc i2'0,10,8,6,4,2,1'                   ; amplitudes of each harmonic
PhaseTbl            dc i2'0,1,2,4,6,8,10'                   ; high word of each fixed phase
PhaseTblF           dc i4'0,6554,13107,26214,39321,52428,$FFFF'
TempValue           ds 10               ; intermediate result storage
TempFactor          ds 10
Temp1               ds 10
Temp2               ds 10
FFTWave             ds 2560             ; table to hold intermediate values
MyDecForm           dc i2'1'
                    dc i2'8'            ; 8 digits after the decimal place
TempI               ds 2
TempF               ds 4
Const127            dc i2'79'
Const80Fix          dc i4'$004F000'
Const10             dc i2'10'
                    end


                    EJECT
*******************************************************************************
*
SANEHarmWave        start
*
* Description:      Create a complex harmonic wave using SANE
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:
*                   Import SaneFFTIteration
*                   Import DoNormI
*
* Entry Points:
*
*******************************************************************************

                    using Globals
                    using FFTransData
                    using SANEequs

                    PushLong #ContRect  ; first, start with a clean screen
                    _EraseRect          ; by erasing the old screen

                    PushWord #10        ; label the bottom of the window
                    PushWord #170       ; to show what we are doing
                    _MoveTo
                    
                    PushLong #SANEHarmTitle
                    _DrawString
                    

                    PushWord #0         ; start this drawing off
                    PushWord #80        ; at the left edge
                    _MoveTo

                    stz Sample          ; and zero out all global values
                    STZEXT MaxValue
                    STZEXT temp1
                    STZEXT temp2
                    STZEXT tempFactor

DHWLoop1            jsr SaneFFTIteration ; do one iteration

                    lda Sample          ; now save tempValue into our array
                    asl a               ; multiply by 2
                    sta Temp1           ; and save it for a sec
                    asl a
                    asl a               ; multiply by 8
                    clc
                    adc Temp1           ; x*8+x*2=x*10
                    tax                 ; use as an index into the sample array

                    lda TempValue       ; now stow the current value
                    sta FFTWave,x       ; into our wave table. Later this
                    lda TempValue+2     ; table will be normalized
                    sta FFTWave+2,x
                    lda TempValue+4
                    sta FFTWave+4,x
                    lda TempValue+6
                    sta FFTWave+6,x
                    lda TempValue+8
                    sta FFTWave+8,x

                    inc Sample          ; bump the sample counter
                    lda #255
                    cmp Sample          ; test to see if we have reached the 
                    bge DHWLoop1        ; last sample, if not do the next one

; if the last sample was reached, it is time to go thru the wavetable and
; convert all the number so they are between 0 and 160.
                    
                    stz Count           ; initialize the index
DHWLoop2            inc Count
                    jsr DoNormI         ; normalize one iteration

                    PushWord Count      ; X coordinate
                    PushWord TempValue  ; value returned by DoNormI
                    _LineTo             ; draw the line

                    lda #255            ; see if the counter has reached the max
                    cmp Count           ; sample we recorded
                    bge DHWLoop2        ; if not, do another point


                    rts                 ; if it has, then we can simply end
                    end
                    
                    EJECT
*******************************************************************************
*
SaneFFTIteration    start
*
* Description:      This routine takes the current sample value and computes
*                   all the harmonic components that make up the wave for that
*                   sample.
*
*
* Inputs:           Sample - current sample to compute for
*
* Outputs:          TempValue - output sample value
*
* External Refs:
*
* Entry Points:
*
*******************************************************************************
                    using Globals
                    using FFTransData
                    using SANEequs

                    STZEXT TempValue

                    PushLong #Sample
                    PushLong #tempFactor
                    FI2X                ; convert the max sample rate to extended

                    PushLong #MaxSample
                    PushLong #Temp1
                    FI2X

                    PushLong #Temp1
                    PushLong #tempFactor
                    FDIVX               ; tempFactor:=tempFactor/temp1

                    PushLong #twoPi
                    PushLong #TempFactor
                    FMULX               ; TempFactor:=6.28318*(count/maxSample)

                    stz Count           ; zero out the counter

FFLoop              ANOP
                    ExtendEq twoPi,Temp2

                    lda Count           ; get the count
                    asl a               ; multiply by 2
                    tax
                    lda PhaseTbl,x
                    sta TempI
                    PushLong #TempI
                    PushLong #temp1
                    FI2X                ; Temp1:=Phase[count]

                    PushLong #Const10
                    PushLong #Temp1
                    FDIVI               ; divide by 10 to make it fractional

                    PushLong #Temp1
                    PushLong #Temp2
                    FMulX               ; temp2:=(temp1)/10*twoPi

                    ExtendEq tempFactor,temp1

                    PushLong #Count
                    PushLong #Temp1
                    FMULI               ; tempi:=count*tempFactor

                    PushLong #Temp2
                    PushLong #Temp1
                    FADDX               ; temp1:=((count*tempFactor)+(6.28318*Phase[count]))

                    PushLong #Temp1
                    FCOSX               ; temp1:=Cos(temp1)

                    lda Count           ; get the count
                    asl a               ; multiply by 2
                    tax
                    lda AmpTbl,x
                    sta TempI
                    PushLong #TempI
                    PushLong #Temp1
                    FMULI               ; temp1:=temp1*Amp[count]

                    PushLong #Temp1
                    PushLong #TempValue
                    FADDX               ; finally tempValue:=tempValue+temp1

                    PushLong #TempValue
                    PushLong #Temp1
                    FX2X                ; copy tempvalue into temp1

                    PushLong #Temp1
                    FABSX

                    PushLong #Temp1
                    PushLong #MaxValue
                    FCMPX               ; now update the max value if needed

                    FBLE FFTL010        ; if the new number <= old max ignore next line

                    ExtendEq Temp1,MaxValue

FFTL010             ANOP
                    inc Count
                    lda Count
                    cmp MaxHarm         ; are we done yet???
                    bge FFTDone
                    brl FFLoop
FFTDone             rts
                    end

                    EJECT
*******************************************************************************
*
DoNormI             start
*
* Description:      Normalize one iteration of the wavetable. This routine
*                   takes the current sample value and converts it to 
*
*
* Inputs:           Count - current sample number
*
* Outputs:          TempValue - the normalized value
*
* External Refs:    None
*
* Entry Points:     None
*
*******************************************************************************
                    using Globals
                    using FFTransData
                    using SANEequs

                    lda Count
                    asl a               ; multiply by 2
                    sta Temp1           ; and save it for a sec
                    asl a
                    asl a               ; multiply by 8
                    clc
                    adc Temp1           ; x*8+x*2=x*10
                    tax

                    lda FFTWave,x       ; now load the current value
                    sta TempValue
                    lda FFTWave+2,x
                    sta TempValue+2
                    lda FFTWave+4,x
                    sta TempValue+4
                    lda FFTWave+6,x
                    sta TempValue+6
                    lda FFTWave+8,x
                    sta TempValue+8

                    ExtendEq MaxValue,temp2

                    PushLong #Temp2
                    PushLong #TempValue ; divide the two
                    FDIVX

                    PushLong #Const127  ; now scale it
                    PushLong #TempValue
                    FMULI

                    PushLong #Const127
                    PushLong #TempValue
                    FADDI

                    PushLong #TempValue ; now, convert ot to an integer
                    PushLong #TempI
                    FX2I

                    lda TempI
                    sta TempValue
                    rts
                    end



                    EJECT
*******************************************************************************
*
IntHarmWave         start
*
* Description:      This routine will create a complex waveformusing the 
*                   integer math tools
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:
*                   Import IntFFTIteration
*                   Import IntHarmI
*
* Entry Points:
*
*******************************************************************************
                    using Globals
                    using FFTransData

                    PushLong #ContRect  ; first, start with a clean screen
                    _EraseRect          ; by erasing the old screen

                    PushWord #10        ; label the bottom of the window
                    PushWord #170       ; to show what we are doing
                    _MoveTo
                    
                    PushLong #IntHarmTitle
                    _DrawString
                    
                    PushWord #0         ; start this drawing off
                    PushWord #80
                    _MoveTo

                    stz Sample          ; zero out some starting values
                    STZL MaxValue
                    STZL temp1
                    STZL temp2
                    STZL tempFactor


DIWLoop1            jsr IntFFTIteration ; do one iteration of the wave

                    lda Sample          ; now save tempValue into our array
                    asl a               ; multiply by 2
                    asl a
                    tax

                    lda TempValue       ; now stow the temp value
                    sta FFTWave,x       ; into an array for later use
                    lda TempValue+2
                    sta FFTWave+2,x

                    inc Sample          ; bump the sample counter
                    lda #255            
                    cmp Sample          ; see if we are done
                    bge DIWLoop1        ; if not, get another sample

; Now that the array of values has been created. Go thru and scale
; each value so that it fits in our wave and is between 0 and 160

                    stz Count           ; zero the sample counter
DIWLoop2            inc Count
                    jsr IntHarmI        ; normalize one iteration

                    PushWord Count      ; X coordinate
                    PushWord TempValue
                    _LineTo             ; draw the line

                    lda #255
                    cmp Count
                    bge DIWLoop2

                    rts
                    end

                    EJECT
*******************************************************************************
*
IntFFTIteration     start
*
* Description:      This routine will calculate one single iteration of the 
*                   wave. It will add a the Cosine*amp of each desired
*                   harmonic to create a single sample
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:
*
* Entry Points:
*
*******************************************************************************
                    using Globals
                    using FFTransData

                    stzL TempValue

                    LongResult           ; push room on the stack
                    LongResult           ; push room on the stack
                    PushLong FixSamp    ; sample fixed number format
                    PushLong FixMaxSamp ; max sample fixed point number
                    _FixDiv

                    PushLong TwoPiFix
                    _FixMul             ; now multiply the two to get theFactor
                    PullLong tempFactor


                    stz Count           ; zero out the counter

FFLoop              ANOP

                    lda Count           ; get the count
                    asl a               ; multiply by 2
                    asl a
                    tax
                    lda PhaseTblF,x
                    sta TempF
                    lda PhaseTblF+2,X
                    sta TempF+2

                    LongResult           ; push room on the stack
                    PushLong TwoPiFix
                    PushLong TempF
                    _FixMul             ; temp2:=Phase(Count)*twoPi
                    PullLong Temp2

                    LongResult           ; push room on the stack
                    PushLong FixCount
                    PushLong TempFactor
                    _FixMul             ; temp1:=count*tempFactor
                    PullLong Temp1

                    lda Temp1           ; temp2:=temp1+temp2
                    clc
                    adc Temp2
                    sta Temp2
                    lda Temp1+2
                    adc Temp2+2
                    sta Temp2+2

                    LongResult           ; push room on the stack
                    LongResult           ; push room on the stack
                    LongResult           ; push room on the stack
                    PushLong Temp2
                    _FracCos            ; temp2:=Cos(temp2)
                    _Frac2Fix           ; convert back to fixed!
                    PullLong Temp2

                    PushLong Temp2
                    lda Count           ; get the count
                    asl a               ; multiply by 2
                    tax
                    lda AmpTbl,x
                    pha
                    pea $0              ; Low word of fixed count
                    _FixMul             ; temp1:=temp1*Amp[count]
                    PullLong Temp2

                    lda TempValue       ; now add it to tempValue
                    clc
                    adc Temp2
                    sta TempValue
                    sta Temp2
                    lda TempValue+2
                    adc Temp2+2
                    sta TempValue+2     ; Now test for max value
                    sta Temp2+2
                    bpl TestHigh        ; number is positive, test for high
                    lda #0              ; Negate this number to get absolute value
                    sec
                    sbc Temp2           ; negate this number
                    sta Temp2
                    lda #0
                    sbc Temp2+2
                    sta Temp2+2
TestHigh            lda Temp2+2
                    cmp MaxValue+2      ; is it bigger than max value+2?
                    beq FFTTestLow      ; if equal test the low byte
                    bge FFTStoreMax     ; if greater move it to high
                    bra FFTL010
FFTTestLow          lda Temp2
                    cmp MaxValue        ; is it bigger?
                    blt FFTL010
FFTStoreMax         lda Temp2+2
                    sta MaxValue+2
                    lda Temp2
                    sta MaxValue

FFTL010             ANOP
                    inc Count
                    lda Count
                    cmp MaxHarm         ; are we done yet???
                    bge FFTDone
                    brl FFLoop
FFTDone             rts
                    end

                    EJECT
*******************************************************************************
*
IntHarmI            start
*
* Description:      Takes an iteration of the wave divides it by the max value
*                   and multiplies it by 160 to create a valid screen location
*
*
* Inputs:           None
*
* Outputs:          None
*
* External Refs:
*
* Entry Points:
*
*******************************************************************************
                    using Globals
                    using FFTransData

                    lda Count
                    asl a               ; multiply by 4
                    asl a
                    tax
                    lda FFTWave+2,x     ; push current value on stack
                    sta Temp1+2
                    lda FFTWave,x       ; 
                    sta Temp1

                    LongResult           ; push room on the stack
                    LongResult           ; push room on the stack
                    PushLong Temp1
                    PushLong MaxValue   ; divide it by maxvalue
                    _FixDiv
                    PullLong Temp2

                    PushLong Temp2
                    PushWord #$4F
                    PushWord #0         ; now scale it
                    _FixMul
                    PullLong Temp1

                    lda Temp1+2
                    clc
                    adc #79
                    sta TempValue
                    rts
                    end

                    copy Math.Init.aii

                    END
